/*
 * @(#)Contour.java
 *
 * Copyright 2002 JIDE Software Inc. All rights reserved.
 */
package com.element.swing.base;

import com.element.plaf.UIDefaultsLookup;
import com.element.swing.IContour;
import com.element.swing.MacOSCursors;
import com.element.ui.pane.JideSplitPane;
import com.element.ui.pane.JideSplitPaneDivider;

import javax.swing.*;
import java.awt.*;

/**
 * A <code>Contour</code> is a lightweight component which only paints the outline of component when dragged. It is also
 * used as a placeholder for some information during dragging.
 * <p/>
 * Notes: this class has to be public so that JIDE can use it in different packages, not meant to release to end user as
 * a public API. JIDE will not guarantee the class will remain as it is.
 */
public class Contour extends JComponent implements IContour {
	public static final int PARTIAL_OUTLINE_MODE = 0;

	public static final int MIX_OUTLINE_MODE = 1;

	public static final int FULL_OUTLINE_MODE = 2;

	// Five values below should be configurable

	/**
	 * width of the contour.
	 */
	private int _thickness;

	/**
	 * the width of tab if in tab-docked mode.
	 */
	private static final int TAB_WIDTH = 42;

	/**
	 * the distance from the beginning to the tab if in tab-docked mode.
	 */
	private static final int TAB_LEADING = 8;

	/**
	 * the color of contour.
	 */
	private Color _lineColor = new Color(136, 136, 136); // to fake the old contour color
//    private static final Color LINE_COLOR = Color.BLACK;

	/*
	 * the stroke to paint special effect of a contour.
	 */
//    private static final BasicStroke DOTTED_STROKE = new BasicStroke(1.0f, BasicStroke.CAP_SQUARE,
//            BasicStroke.JOIN_ROUND, 1.0f, new float[]{0, 2, 0, 2}, 0);;

	/**
	 * height of tab. It was used to draw contour. Application can set the height.
	 */
	private int _tabHeight = 22;

	/**
	 * <code>true</code> if docking is allowed; <code>false</code> otherwise. Usually when user pressed ctrl key, dock
	 * is not allowed.
	 */
	private boolean _allowDocking = true;

	/**
	 * <code>true</code> if tab-docked; <code>false</code> otherwise.
	 */
	private boolean _tabDocking;

	/**
	 * Which side is the tab
	 */
	private int _tabSide;

	/**
	 * <code>true</code> if float; <code>false</code> otherwise.
	 */
	private boolean _floating;

	/**
	 * which component the dragged component will dock to.
	 */
	private Component _attachedComponent;

	/**
	 * which side the dragged component will dock to.
	 */
	private int _attachedSide;

	/**
	 * When you dragged a component, several other components could be dragged. For example, if user drags on title bar
	 * of FrameContainer, all components in the FrameContainer are considered as dragged. If user drags on tab, only
	 * selected one is dragged.
	 * <p/>
	 * <code>true</code> if all dragged components are affected; <code>false</code> otherwise.
	 */
	private boolean _single;

	/**
	 * When user press and release ctrl key, the contour will toggle between dock and float mode. These three fields are
	 * used to remember previous state.
	 */
	private JComponent _saveDraggedComponent;
	private int _saveX, _saveY;
	private int _saveMouseModifier;

	private Container _relativeContainer;

	private int _outlineMode = 0;

	private Outline _topOutline;
	private Outline _bottomOutline;
	private Outline _leftOutline;
	private Outline _rightOutline;

	/**
	 * If ghost is true, it will not paint itself at all but paint to underlying LayerPane.
	 */
	private boolean _ghost = false;

	private Component _glassPane;

	private boolean _changeCursor = false;

	/**
	 * Default Constructor.
	 */
	public Contour() {
		this(22);
		setOpaque(false);
		setDoubleBuffered(true);
	}

	/**
	 * Constructor with tab height.
	 *
	 * @param tabHeight the tab height
	 */
	public Contour(int tabHeight) {
		_thickness = UIDefaultsLookup.getInt("Contour.thickness") == 0 ? 4 : UIDefaultsLookup.getInt("Contour.thickness");
		_lineColor = UIDefaultsLookup.getColor("Contour.color") == null ? new Color(136, 136, 136) : UIDefaultsLookup.getColor("Contour.color");
		setTabHeight(tabHeight);
		if (getOutlineMode() != PARTIAL_OUTLINE_MODE) {
			initOutline();
		}
	}

	private void initOutline() {
//        System.out.println("1");
		_topOutline = new Outline();
		_bottomOutline = new Outline();
		_leftOutline = new Outline();
		_rightOutline = new Outline();
	}

	/**
	 * Returns whether this component should use a buffer to paint.
	 *
	 * @return true if this component is double buffered, otherwise false
	 */
	@Override
	public boolean isDoubleBuffered() {
		return true;
	}

	/**
	 * Paint a rectangle or tab-shape using <code>DOTTED_STROKE<code> with width of <code>WIDTH<code>.
	 *
	 * @param g
	 */
	@Override
	public void paint(Graphics g) {
		if (!_ghost) {
			paintOutline(g, false);
		}
	}

	private void paintOutline(Graphics g, boolean xorMode) {
		Rectangle bounds = getBounds();
		g.translate(-bounds.x, -bounds.y);

		if (xorMode) {
			bounds = SwingUtilities.convertRectangle(this, bounds, (getRelativeContainer() != null ? getRelativeContainer() : getParent()));
//            System.out.println(bounds);
		} else {
			g.setColor(_lineColor);
		}
// comment to make it draw faster
//        ((Graphics2D)g).setStroke(DOTTED_STROKE);

		if (getOutlineMode() != FULL_OUTLINE_MODE && isTabDocking()) {
			drawTab(g, bounds.x, bounds.y, bounds.width, bounds.height - 1,
					_tabHeight - 1, TAB_WIDTH, TAB_LEADING,
					_thickness, getTabSide());
		} else {
			drawRect(g, bounds.x, bounds.y, bounds.width - 1, bounds.height - 1, _thickness);
		}
	}

	/**
	 * Draws vertical orhorizontall lines. Try to test if fillRect then drawLine four times. Other unit test show it's
	 * about fillRect is 75% faster than drawLine, so we decide to use fillRect to draw the contour.
	 *
	 * @param g
	 * @param x1
	 * @param y1
	 * @param x2
	 * @param y2
	 * @param thick
	 */
	private static void drawLine(Graphics g, int x1, int y1, int x2, int y2, int thick) {
		if (x1 == x2) {
			if (y2 > y1) {
				g.fillRect(x1, y1, thick, y2 - y1);
			} else {
				g.fillRect(x1, y2, thick, y1 - y2);
			}
		} else if (y1 == y2) {
			if (x2 > x1) {
				g.fillRect(x1, y1, x2 - x1, thick);
			} else {
				g.fillRect(x2, y1, x1 - x2, thick);
			}
		}

	}

	private static void drawRect(Graphics g, int x, int y, int width, int height, int thick) {
		if (width <= thick) {
			drawLine(g, x, y, x, y + height, thick);
		} else if (height <= thick) {
			drawLine(g, x, y, x + width, y, thick);
		} else {
			drawLine(g, x, y, x + width - thick, y, thick);
			drawLine(g, x + width - thick, y, x + width - thick, y + height - thick, thick);
			drawLine(g, x + width, y + height - thick, x + thick, y + height - thick, thick);
			drawLine(g, x, y + height, x, y + thick, thick);
		}
// commented because of using fillRect
//        g.drawLine(x, y, x + width - 1, y);
//        g.drawLine(x + width, y, x + width, y + height - 1);
//        g.drawLine(x + width, y + height, x + 1, y + height);
//        g.drawLine(x, y + height, x, y + 1);
	}

	private static void drawTab(Graphics g, int x, int y, int width, int height, int tabHeight, int tabWidth, int tabLeading, int thick, int side) {
		switch (side) {
			case SwingConstants.TOP -> drawTopTab(g, x, y, width, height, tabHeight, tabWidth, tabLeading, thick);
			case SwingConstants.BOTTOM -> drawBottomTab(g, x, y, width, height, tabHeight, tabWidth, tabLeading, thick);
		}
	}

//         TabDocking
//            |------
//            |     |
//         |---     |--------
//         |                |
//         |                |
//         |                |
//         |                |
//         |                |
//         -----------------|

	private static void drawTopTab(Graphics g, int x, int y, int width, int height, int tabHeight, int tabWidth, int tabLeading, int thick) {
		drawLine(g, x + width - thick, y + tabHeight, x + width - thick, y + height - 1, thick); // right

		drawLine(g, x + tabLeading + thick, y + tabHeight, x, y + tabHeight, thick); // top leading
		drawLine(g, x + tabWidth + tabLeading, y + tabHeight, x + tabWidth + tabLeading, y, thick); // tab right
		drawLine(g, x + tabWidth + tabLeading, y, x + tabLeading + 1, y, thick); // tab top
		drawLine(g, x + tabLeading, y, x + tabLeading, y + tabHeight, thick); // tab left
		drawLine(g, x + width, y + tabHeight, x + tabWidth + tabLeading, y + tabHeight, thick); // top rest

		drawLine(g, x, y + tabHeight, x, y + height, thick); // left

		drawLine(g, x, y + height - thick, x + width, y + height - thick, thick); // bottom

// commented because of using fillRect
//        g.drawLine(x, y, x + width - 1, y); // top
//        g.drawLine(x + width, y, x + width, y + height - tabHeight - 1); // right
//
//        g.drawLine(x + width, y + height - tabHeight, x + tabWidth + tabLeading + 1, y + height - tabHeight); // bottom rest
//        g.drawLine(x + tabWidth + tabLeading, y + height - tabHeight, x + tabWidth + tabLeading, y + height - 1); // tab right
//        g.drawLine(x + tabWidth + tabLeading, y + height, x + tabLeading + 1, y + height); // tab bottom
//        g.drawLine(x + tabLeading, y + height, x + tabLeading, y + height - tabHeight + 1); // tab left
//        g.drawLine(x + tabLeading, y + height - tabHeight, x + 1, y + height - tabHeight); // bottom leading
//
//        g.drawLine(x, y + height - tabHeight, x, y + 1); // left
	}

//         TabDocking
//         -----------------|
//         |                |
//         |                |
//         |                |
//         |                |
//         |                |
//         |---     |--------
//            |     |
//            |------

	private static void drawBottomTab(Graphics g, int x, int y, int width, int height, int tabHeight, int tabWidth, int tabLeading, int thick) {
		drawLine(g, x, y, x + width - 1, y, thick); // top
		drawLine(g, x + width - thick, y, x + width - thick, y + height - tabHeight - 1, thick); // right

		drawLine(g, x + width, y + height - tabHeight - thick, x + tabWidth + tabLeading, y + height - tabHeight - thick, thick); // bottom rest
		drawLine(g, x + tabWidth + tabLeading, y + height - tabHeight, x + tabWidth + tabLeading, y + height, thick); // tab right
		drawLine(g, x + tabWidth + tabLeading, y + height - thick, x + tabLeading + 1, y + height - thick, thick); // tab bottom
		drawLine(g, x + tabLeading, y + height, x + tabLeading, y + height - tabHeight, thick); // tab left
		drawLine(g, x + tabLeading + thick, y + height - tabHeight - thick, x + 1, y + height - tabHeight - thick, thick); // bottom leading

		drawLine(g, x, y + height - tabHeight, x, y + 1, thick); // left

// commented because of using fillRect
//        g.drawLine(x, y, x + width - 1, y); // top
//        g.drawLine(x + width, y, x + width, y + height - tabHeight - 1); // right
//
//        g.drawLine(x + width, y + height - tabHeight, x + tabWidth + tabLeading + 1, y + height - tabHeight); // bottom rest
//        g.drawLine(x + tabWidth + tabLeading, y + height - tabHeight, x + tabWidth + tabLeading, y + height - 1); // tab right
//        g.drawLine(x + tabWidth + tabLeading, y + height, x + tabLeading + 1, y + height); // tab bottom
//        g.drawLine(x + tabLeading, y + height, x + tabLeading, y + height - tabHeight + 1); // tab left
//        g.drawLine(x + tabLeading, y + height - tabHeight, x + 1, y + height - tabHeight); // bottom leading
//
//        g.drawLine(x, y + height - tabHeight, x, y + 1); // left
	}

	/**
	 * Overwrite setBounds so that width and height are always even.
	 *
	 * @param r the new bounding rectangle for this component
	 */
	@Override
	public void setBounds(Rectangle r) {
		setBounds(r.x, r.y, r.width, r.height);
	}

	/**
	 * Overwrite setBounds so that width and height are always even.
	 * <p/>
	 * It looks ugly for either dimension is odd when painting with <code>DOTTED_STROKE</code>
	 *
	 * @param x      the new <i>x</i>-coordinate of this component
	 * @param y      the new <i>y</i>-coordinate of this component
	 * @param width  the new <code>width</code> of this component
	 * @param height the new <code>height</code> of this component
	 */
	@Override
	public void setBounds(int x, int y, int width, int height) {
		if (isLightweight()) {
			if (getOutlineMode() == PARTIAL_OUTLINE_MODE) {
				if (_ghost && (getRelativeContainer() != null || getParent() != null)) {
					Graphics g = (getRelativeContainer() != null ? getRelativeContainer() : getParent()).getGraphics();
					g.setXORMode(_lineColor);
					paintOutline(g, true);
					super.setBounds(x, y,
							width % 2 == 0 ? width + 1 : width,
							height % 2 == 0 ? height + 1 : height);
//                    paintOutline(g, true);
				} else {
					super.setBounds(x, y,
							width % 2 == 0 ? width + 1 : width,
							height % 2 == 0 ? height + 1 : height);
				}
			} else {
				Rectangle rectangle = new Rectangle(x, y,
						width % 2 == 0 ? width + 1 : width,
						height % 2 == 0 ? height + 1 : height);
				if (getParent() != null) {
					Rectangle parentRectangle = getParent().getBounds();
					super.setBounds(x, y,
							width % 2 == 0 ? width + 1 : width,
							height % 2 == 0 ? height + 1 : height);
					if (getOutlineMode() == MIX_OUTLINE_MODE && parentRectangle.contains(rectangle)) {
						_leftOutline.setVisible(false);
						_rightOutline.setVisible(false);
						_topOutline.setVisible(false);
						_bottomOutline.setVisible(false);
					} else {
						super.setVisible(false);
						Point point = rectangle.getLocation();
						SwingUtilities.convertPointToScreen(point, getParent());
						arrangeOutline(rectangle, point);
					}
				}
			}
		} else {
			if (getRelativeContainer() != null) {
				Point point = new Point(x, y);
				SwingUtilities.convertPointToScreen(point, getRelativeContainer());
				super.setBounds(point.x, point.y,
						width % 2 == 0 ? width + 1 : width,
						height % 2 == 0 ? height + 1 : height);
			}
		}
	}

	private void arrangeOutline(Rectangle rectangle, Point point) {
//        boolean beyondLeft = rectangle.x < 0;
//        boolean beyondTop = rectangle.y < 0;
//        boolean beyondRight = rectangle.x + rectangle.width > parentRectangle.x + parentRectangle.width;
//        boolean beyondBottom = rectangle.y + rectangle.height > parentRectangle.y + parentRectangle.height;
		_leftOutline.setBounds(point.x, point.y, _thickness, rectangle.height - _thickness);
		_topOutline.setBounds(point.x + _thickness, point.y, rectangle.width - _thickness - 1, _thickness);
		_rightOutline.setBounds(point.x + rectangle.width - _thickness - 1, point.y + _thickness, _thickness, rectangle.height - _thickness);
		_bottomOutline.setBounds(point.x, point.y + rectangle.height - _thickness, rectangle.width - 1, _thickness);
		if (!_topOutline.isVisible()) {
			_topOutline.setVisible(true);
		}
		if (!_leftOutline.isVisible()) {
			_leftOutline.setVisible(true);
		}
		if (!_rightOutline.isVisible()) {
			_rightOutline.setVisible(true);
		}
		if (!_bottomOutline.isVisible()) {
			_bottomOutline.setVisible(true);
		}
	}

	/**
	 * Gets tab height.
	 *
	 * @return tab height
	 */
	public int getTabHeight() {
		return _tabHeight;
	}

	/**
	 * Sets the tab height.
	 *
	 * @param tabHeight
	 */
	public void setTabHeight(int tabHeight) {
		_tabHeight = tabHeight;
	}

	/**
	 * Returns true if the contour is in tab-dock mode.
	 *
	 * @return true if tab-docking; false otherwise
	 */
	public boolean isTabDocking() {
		return _tabDocking;
	}

	/**
	 * Sets the tab-docking mode.
	 *
	 * @param tabDocking new mode
	 */
	public void setTabDocking(boolean tabDocking) {
		_tabDocking = tabDocking;
		updateCursor();
	}

	/**
	 * Gets the side of the tab.
	 *
	 * @return the side of the tab
	 */
	public int getTabSide() {
		return _tabSide;
	}

	/**
	 * Sets the side of the tab.
	 *
	 * @param tabSide
	 */
	public void setTabSide(int tabSide) {
		_tabSide = tabSide;
	}

	/**
	 * Returns true if the contour is in floating mode.
	 *
	 * @return true if floating; false otherwise
	 */
	public boolean isFloating() {
		return _floating;
	}

	/**
	 * Sets the floating mode.
	 *
	 * @param floating new mode
	 */
	public void setFloating(boolean floating) {
		_floating = floating;
		updateCursor();
	}

	/**
	 * Gets the attached component of this contour.
	 *
	 * @return the attached component
	 */
	public Component getAttachedComponent() {
		return _attachedComponent;
	}

	/**
	 * Sets the attached components.
	 *
	 * @param attachedComponent attached component to be set
	 */
	public void setAttachedComponent(Component attachedComponent) {
		_attachedComponent = attachedComponent;
	}

	/**
	 * Gets the side of the attached component which the contour is attached to.
	 *
	 * @return side the attached side
	 */
	public int getAttachedSide() {
		return _attachedSide;
	}

	/**
	 * Sets the side of the attached component which the contour is attached to.
	 *
	 * @param attachedSide the new attached side to be set
	 */
	public void setAttachedSide(int attachedSide) {
		_attachedSide = attachedSide;
		updateCursor();
	}

	private void updateCursor() {
		if (getGlassPane() == null) { // if glass pane is not set, no way to change cursor shape.
			return;
		}

		// show a stop cursor if the floating is not allowed
		if (!isVisible() && _floating) {
			getGlassPane().setCursor(MacOSCursors.NOT_ALLOWED_CURSOR.CURSOR);
			return;
		} else {
			getGlassPane().setCursor(Cursor.getDefaultCursor());
		}

		if (!_changeCursor) {
			return;
		}

		if (!isVisible()) {
			getGlassPane().setCursor(Cursor.getDefaultCursor());
			return;
		}

		if (isVisible() && (!_allowDocking || _floating)) {
			getGlassPane().setCursor(MacOSCursors.MOVE_CURSOR.CURSOR);
		} else if (isVisible() && _tabDocking) {
			getGlassPane().setCursor(MacOSCursors.POINTER_CURSOR.CURSOR);
		} else if (getAttachedComponent() instanceof JideSplitPaneDivider) {
			if (((JideSplitPaneDivider) getAttachedComponent()).getJideSplitPane().getOrientation() == JideSplitPane.HORIZONTAL_SPLIT) {
				getGlassPane().setCursor(MacOSCursors.LEFT_RIGHT_CURSOR.CURSOR);
			} else {
				getGlassPane().setCursor(MacOSCursors.UP_DOWN_CURSOR.CURSOR);
			}
		} else {
			switch (_attachedSide) {
				case 1 -> getGlassPane().setCursor(MacOSCursors.NORTH_CURSOR.CURSOR);
				case 2 -> getGlassPane().setCursor(MacOSCursors.SOUTH_CURSOR.CURSOR);
				case 4 -> getGlassPane().setCursor(MacOSCursors.EAST_CURSOR.CURSOR);
				case 8 -> getGlassPane().setCursor(MacOSCursors.WEST_CURSOR.CURSOR);
				default -> getGlassPane().setCursor(Cursor.getDefaultCursor());
			}
		}
	}

	/**
	 * When you dragged a component, several other components could be dragged. For example, if user drags on title bar
	 * of FrameContainer, all components in the FrameContainer are considered as dragged. If user drags on tab, only
	 * selected one is dragged.
	 *
	 * @return <code>true</code> if all dragged components are affected; <code>false</code> otherwise.
	 */
	public boolean isSingle() {
		return _single;
	}

	/**
	 * Sets the value of single.
	 *
	 * @param single <code>true</code> if all dragged components are affected; <code>false</code> otherwise.
	 */
	public void setSingle(boolean single) {
		_single = single;
	}

	/**
	 * Checks if docking is allowed.
	 *
	 * @return <code>true</code> if docking is allowed; <code>false</code> otherwise.
	 */
	public boolean isAllowDocking() {
		return _allowDocking;
	}

	/**
	 * Sets the value of docking.
	 *
	 * @param allowDocking <code>true</code> if docking is allowed; <code>false</code> otherwise.
	 */
	public void setAllowDocking(boolean allowDocking) {
		_allowDocking = allowDocking;
		updateCursor();
	}

	public Container getRelativeContainer() {
		return _relativeContainer;
	}

	public void setRelativeContainer(Container relativeContainer) {
		_relativeContainer = relativeContainer;
	}

	/**
	 * Gets saved X position of contour before it's hidden.
	 *
	 * @return saved X position
	 */
	public int getSaveX() {
		return _saveX;
	}

	/**
	 * Gets saved Y position of contour before it's hidden.
	 *
	 * @return saved Y position
	 */
	public int getSaveY() {
		return _saveY;
	}

	/**
	 * Gets saved mouse modifier before the contour is hidden.
	 *
	 * @return saved mouse modifier
	 */
	public int getSaveMouseModifier() {
		return _saveMouseModifier;
	}

	/**
	 * Gets saved dragged component before the contour is hidden.
	 *
	 * @return saved dragged component
	 */
	public JComponent getSaveDraggedComponent() {
		return _saveDraggedComponent;
	}

	/**
	 * Stores information before the contour is hidden. Those information will be used to restore when the contour is
	 * set visible again.
	 *
	 * @param comp              the dragged component
	 * @param saveX             X position of the contour
	 * @param saveY             Y position of the contour
	 * @param saveMouseModifier mouse modifier in the MouseEvent
	 */
	public void setDraggingInformation(JComponent comp, int saveX, int saveY, int saveMouseModifier) {
		_saveDraggedComponent = comp;
		_saveX = saveX;
		_saveY = saveY;
		_saveMouseModifier = saveMouseModifier;
	}

	public void cleanup() {
		if (getOutlineMode() != PARTIAL_OUTLINE_MODE) {
//            System.out.println("0");
			_leftOutline.dispose();
			_rightOutline.dispose();
			_topOutline.dispose();
			_bottomOutline.dispose();
			_leftOutline = null;
			_rightOutline = null;
			_topOutline = null;
			_bottomOutline = null;
		}
		if (getGlassPane() != null) {
			getGlassPane().setCursor(Cursor.getDefaultCursor());
		}
	}

//    private Screen _screen;
//    private Container _savedContainer;

	/**
	 * Makes the component visible or invisible. Overrides <code>Component.setVisible</code>.
	 *
	 * @param aFlag true to make the component visible; false to make it invisible
	 */
	@Override
	public void setVisible(boolean aFlag) {
		super.setVisible(aFlag);
		updateCursor();
		if (!aFlag && getOutlineMode() != PARTIAL_OUTLINE_MODE) {
			_leftOutline.setVisible(false);
			_rightOutline.setVisible(false);
			_topOutline.setVisible(false);
			_bottomOutline.setVisible(false);
		}
	}

	/**
	 * Determines whether this component should be visible when its parent is visible. Components are initially visible,
	 * with the exception of top level components such as <code>Frame</code> objects.
	 *
	 * @return <code>true</code> if the component is visible, <code>false</code> otherwise
	 * @see #setVisible
	 * @since JDK1.0
	 */
	@Override
	public boolean isVisible() {
		if (super.isVisible()) {
			return true;
		} else return getOutlineMode() != PARTIAL_OUTLINE_MODE &&
				(_topOutline.isVisible() || _bottomOutline.isVisible() || _leftOutline.isVisible() || _rightOutline.isVisible());
	}

	class Outline extends JWindow {
		public Outline() {
			this.setVisible(false);
			setBackground(_lineColor);
		}

		@Override
		public void paint(Graphics g) {
			g.setColor(_lineColor);
			g.fillRect(0, 0, getWidth(), getHeight());
		}

// Code for double buffer but doesn't work very well.
//        Image offscreen;
//
//        public void invalidate() {
//            super.invalidate();
//            offscreen = null;
//        }
//
//        public void update(Graphics g) {
//            paint(g);
//        }
//
//        public void paint(Graphics g) {
//            if (offscreen == null) {
//                offscreen = createImage(getSize().width, getSize().height);
//            }
//            Graphics og = offscreen.getGraphics();
//            // Here do something to draw your rectangle
//            // og.setClip(0,0,getSize().width, getSize().height);
//            super.paint(g);
//
//            g.drawImage(offscreen, 0, 0, null);
//            og.dispose();
//        }
	}

	public int getOutlineMode() {
		return _outlineMode;
	}

	public void setOutlineMode(int outlineMode) {
		if (outlineMode != PARTIAL_OUTLINE_MODE && _outlineMode == PARTIAL_OUTLINE_MODE) {
			initOutline();
		}
		_outlineMode = outlineMode;
	}

	public Component getGlassPane() {
		return _glassPane;
	}

	public void setGlassPane(Component glassPane) {
		_glassPane = glassPane;
	}

	public boolean isChangeCursor() {
		return _changeCursor;
	}

	public void setChangeCursor(boolean changeCursor) {
		_changeCursor = changeCursor;
	}
}
